package com.goodcol.plugin.service.impl;

import com.goodcol.plugin.tool.Constants;
import com.goodcol.plugin.dto.SettingsStorageDTO;
import com.goodcol.plugin.service.ExportImportSettingsService;
import com.goodcol.plugin.tool.HttpUtils;
import com.goodcol.plugin.tool.JSON;
import com.goodcol.plugin.tool.ProjectUtils;
import com.goodcol.plugin.tool.StringUtils;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.ide.CopyPasteManager;
import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.InputValidator;
import com.intellij.openapi.ui.Messages;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.TextTransferable;
import com.sun.net.httpserver.HttpServer;
import org.apache.http.HttpHeaders;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.concurrent.CompletableFuture;

/**
 * URL导出导入设置服务实现
 *
 * @author shanhy
 * @version 1.0.0
 */
public class UrlExportImportSettingsServiceImpl implements ExportImportSettingsService {

    /**
     * 默认端口
     * 弹框打开时检测端口是否被占用，如果被占用则基于这个端口依次+1后尝试，找到一个没有被占用的端口后使用
     */
    private final int defaultPort = 34567;

    /**
     * shareUrlPath
     */
    private final String shareUrlPath = "/quickCodeConfig.json";

    /**
     * 导出设置
     *
     * @param settingsStorage 要导出的设置
     */
    @Override
    public void exportConfig(SettingsStorageDTO settingsStorage) {
        // 构造弹框内容
        JPanel panel = new JPanel(new GridBagLayout());

        GridBagConstraints constraints = new GridBagConstraints();
        constraints.anchor = GridBagConstraints.LINE_START;
        constraints.weighty = 1; // 设置垂直权重以占据更多空间

        String url = "http://".concat(this.getLocalAddress()).concat(":34567").concat(shareUrlPath);
        // 添加第一行
        JLabel jLabel1 = new JLabel("URL地址：".concat(url));
        constraints.gridx = 0;
        constraints.gridy = 0;
        constraints.insets = JBUI.insets(8, 10); // 可以通过内边距增加高度
        panel.add(jLabel1, constraints);

        // 添加第二行
        JLabel descLabel = new JLabel("<html>注意：分享期间请勿关闭该弹框，关闭弹框会终止分享，链接不能再被访问。<br/>如果是跨内网访问，请根据实际情况修改IP地址后分享，端口和Path保持不变。</html>");
        constraints.gridx = 0;
        constraints.gridy = 1;
        constraints.insets = JBUI.insets(8, 10, 18, 10); // 可以通过内边距增加高度
        panel.add(descLabel, constraints);

        // 构建dialog
        DialogBuilder dialogBuilder = new DialogBuilder(ProjectUtils.getCurrProject());
        dialogBuilder.setTitle(Constants.TITLE_INFO);
        dialogBuilder.setCenterPanel(panel);
        dialogBuilder.addActionDescriptor(dialogWrapper -> new AbstractAction("复制链接") {
            @Override
            public void actionPerformed(ActionEvent e) {
                CopyPasteManager.getInstance().setContents(new TextTransferable(url));
                Messages.showInfoMessage("Copy Success！", Constants.TITLE_INFO);
            }
        });
        // 启动HTTP服务
        HttpServer httpServer = this.createHttpServer(this.getHttpPort(), JSON.toJsonByFormat(settingsStorage));
        dialogBuilder.addActionDescriptor(dialogWrapper -> new AbstractAction("退出分享") {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 关闭HTTP服务
                if (httpServer != null) {
                    httpServer.stop(0);
                }
                // 关闭并退出
                dialogWrapper.close(DialogWrapper.OK_EXIT_CODE);
            }
        });
        if (httpServer != null) {
            CompletableFuture.runAsync(httpServer::start);
            // 显示窗口
            dialogBuilder.show();
        }
    }

    /**
     * 获取本机IP地址
     */
    private String getLocalAddress() {
        String ip127 = "127.0.0.1";
        try {
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaces.hasMoreElements()) {
                NetworkInterface ni = networkInterfaces.nextElement();

                // 忽略回环接口（loopback）、未启用或非运行状态的接口
                if (ni.isLoopback() || !ni.isUp())
                    continue;

                Enumeration<InetAddress> inetAddresses = ni.getInetAddresses();
                while (inetAddresses.hasMoreElements()) {
                    InetAddress ia = inetAddresses.nextElement();

                    // 过滤掉无效地址、IPv6地址和特定地址
                    if (!ia.isLinkLocalAddress() && ia instanceof Inet4Address
                            && !ia.getHostAddress().equals(ip127)) {

                        // 检查是否满足最后一位不是1的要求
                        String ip = ia.getHostAddress();
                        int lastOctet = Integer.parseInt(ip.split("\\.")[3]);
                        if (lastOctet != 1) {
                            return ip;
                        }
                    }
                }
            }
        } catch (SocketException | NumberFormatException e) {
            ExceptionUtil.rethrow(e);
        }
        return ip127;
    }

    /**
     * getHttpPort
     *
     * @return data
     */
    private int getHttpPort() {
        int port = defaultPort;
        while (!this.isPortAvailable(port)) {
            port++;
        }
        return port;
    }

    /**
     * 检测一个端口是否被占用
     *
     * @param port port
     * @return data
     */
    private boolean isPortAvailable(int port) {
        try (ServerSocket socket = new ServerSocket(port)) {
            // 如果能够成功创建ServerSocket，则表示该端口未被占用
            return true;
        } catch (IOException e) {
            // 发生异常则表示端口已被占用或者有其他问题
            return false;
        }
    }

    /**
     * startHttpServer
     *
     * @param port port
     * @param body body
     */
    private HttpServer createHttpServer(int port, String body) {
        // 创建并启动HTTP服务器，监听默认34567端口
        try {
            HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
            // 设置处理器，处理"/quickCodeConfig.json"路径的请求
            server.createContext(shareUrlPath, t -> {
                t.getResponseHeaders().add(HttpHeaders.CONTENT_TYPE, HttpUtils.getContentTypeJSON());
                byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
                t.sendResponseHeaders(200, bytes.length);
                OutputStream os = t.getResponseBody();
                os.write(bytes);
                os.close();
            });
            return server;
        } catch (IOException e) {
            Messages.showWarningDialog("Create Http Server Failed.", Constants.TITLE_INFO);
        }
        return null;
    }

    /**
     * 导入设置
     *
     * @return 设置信息
     */
    @Override
    public SettingsStorageDTO importConfig() {
        String httpUrl = Messages.showInputDialog("Http URL:", Constants.TITLE_INFO, AllIcons.General.InformationDialog,
                "http://0.0.0.0:".concat(String.valueOf(defaultPort)).concat(shareUrlPath), new InputValidator() {
            @Override
            public boolean checkInput(String inputString) {
                return !StringUtils.isEmpty(inputString);
            }

            @Override
            public boolean canClose(String inputString) {
                return this.checkInput(inputString);
            }
        });
        if (httpUrl == null) {
            return null;
        }
        String result = HttpUtils.get(httpUrl);
        if (result == null) {
            return null;
        }
        // 解析数据
        return JSON.parse(result, SettingsStorageDTO.class);
    }
}
